;analyse par cas
;lisp -> langage intermediaire
;je pense pas qu'elle soient vraiment complete mais elle fait deja beaucoup de trucs

;1. defun
;2. macro
;3. fs

(defun lisp2li (expr env)
  ;si expr est un atome
  (if (atom expr)
      ;alors on teste si c'est une constante
      (if (constantp expr)
          (list :const expr)
          ;ou une variable de l'environnment
          (let ((pos (position expr env)))
            (if pos
                (list :var pos)
                ;(warn "variable inconnue ~s" expr)
                (list :inc expr))))
      ;si expr n'est pas un atome
      (let ((fun (car expr)) (args (cdr expr)))
        (cond
          ;cas du defun
          ;j'associe la fonction a son nom dans la fonction lisp2li
          ;ca sert pour le mcall plus bas
          ((eq 'defun fun)
           (setf (get (first args) :defun)
                 (list
                  :lamdba
                  (length (second args))
                  (lisp2li (third args) (second args)))))
          ;gestion des macros
          ;assez foireuse vu que je sais pas comment elles fonctionnent en realite
          ((macro-function fun)
           (list
            :macro
            fun
            (lisp2li (macroexpand-1 expr) env)))
          ;la il y a les formes speciales
          ;la fonction speciale-form-p me donnait des trucs bizarres
          ;alors j'ai separe tous les cas
          ;il manque surement des formes speciales
          ((eq 'quote fun)
           (cons :const (first args)))
          ((eq 'if fun)
           (list
            :if
            (maplisp2li args env)))
          ;((eq 'cond fun) ;macro
          ; (list
          ;  :cond
          ; (maplisp2li args env)))
          ((eq 'progn fun)
           (list
            :progn
            (maplisp2li args env)))
          ;du coup il faut redefinir le set dans la fonction
          ((eq 'setf fun)
           (setlidefun expr env))
          ;gestion du reste des appels de fonctions
          ((not (null (getlidefun fun)))
           (list
            :mcall
            fun
            (maplisp2li args env)))
          ((fboundp fun)
           (list
            :call
            fun
            (maplisp2li args env)
            ))
          ;cas inutile (a virer)
          ((boundp fun)
           ())   
          ))))

;les petits tests sympatiques
;(lisp2li '(if (< a 0) 1 0) '(a))
;(lisp2li '(defun fact (n) (if (<= n 0) 1 (* n (fact (- n 1))))) ())
;(lisp2li '(defun fibo (n) (if (<= n 0) 1 (+ (fibo (- n 1)) (fibo (- n 2))))) ())
;(lisp2li '(cond ((< a 1) 0) ((> a 1) 1)) '(a))

;rien de sp�cial, c'est la fonction du prof
(defun maplisp2li (lexpr env)
  (if (atom lexpr)
      ()
      (cons
       (lisp2li (first lexpr) env)
       (maplisp2li (rest lexpr) env))))

;verifie si fun est associ� � quelque chose dans l'environnement
(defun getlidefun (fun)
  (get fun :defun))

;redefinition du set
(defun setlidefun (expr env)
  (if (symbolp (second expr))
      (list
       :setv
       expr
       (lisp2li (second expr) env))
      (list
       :setf
       (lisp2li (expr) env))))
      
  